/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.enforcement.hid.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hopes.bizz.common.core.util.StringUtils;
import com.hopes.bizz.common.core.validate.ValidatorUtils;
import com.hopes.bizz.common.core.validate.group.AuditPassGroup;
import com.hopes.bizz.common.core.validate.group.AuditRejectGroup;
import com.hopes.bizz.enforcement.common.constant.FlowConstant;
import com.hopes.bizz.enforcement.common.constant.HidDicConstant;
import com.hopes.bizz.enforcement.common.constant.IntegralEventEnum;
import com.hopes.bizz.enforcement.common.constant.enums.EnforcementSysDictEnum;
import com.hopes.bizz.enforcement.hid.bo.RiskHidHiddenDangerBO;
import com.hopes.bizz.enforcement.hid.bo.RiskHidTaskBo;
import com.hopes.bizz.enforcement.hid.dto.*;
import com.hopes.bizz.enforcement.hid.entity.RiskHidHandleRecordEntity;
import com.hopes.bizz.enforcement.hid.entity.RiskHidHiddenDangerDelayEntity;
import com.hopes.bizz.enforcement.hid.entity.RiskHidHiddenDangerEntity;
import com.hopes.bizz.enforcement.hid.mapper.RiskHidHiddenDangerMapper;
import com.hopes.bizz.enforcement.hid.service.RiskHidHandleRecordService;
import com.hopes.bizz.enforcement.hid.service.RiskHidHiddenDangerDelayService;
import com.hopes.bizz.enforcement.hid.service.RiskHidHiddenDangerService;
import com.hopes.bizz.enforcement.hid.validate.HidAssignGroup;
import com.hopes.bizz.enforcement.hid.vo.RiskHidHiddenDangerExcelVO;
import com.hopes.bizz.enforcement.integral.bo.IntegralEvent;
import com.hopes.boss.act.base.FlowServiceImpl;
import com.hopes.boss.act.base.TaskExecute;
import com.hopes.boss.act.enums.FlowTaskHandlerType;
import com.hopes.boss.act.vo.FlowTaskInfo;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.admin.api.resolver.enums.AdminDictEnum;
import com.hopes.boss.common.core.exception.BizException;
import com.hopes.boss.common.data.tenant.TenantBroker;
import com.hopes.boss.common.entity.ValidateImportBO;
import com.hopes.boss.common.excel.vo.ErrorMessage;
import com.hopes.boss.common.security.util.SecurityUtils;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 隐患信息
 *
 * @author pig
 * @date 2023-07-18 10:51:29
 */
@Service
public class RiskHidHiddenDangerServiceImpl extends FlowServiceImpl<RiskHidHiddenDangerMapper, RiskHidHiddenDangerEntity> implements RiskHidHiddenDangerService {

    @Resource
    private ApplicationEventPublisher eventPublisher;

    @Resource
    private RiskHidHandleRecordService riskHidHandleRecordService;

    @Resource
    private RiskHidHiddenDangerDelayService riskHidHiddenDangerDelayService;

    // 导入前执行
    @Override
    public void beforeImportExcel() {
        RiskHidHiddenDangerService.super.beforeImportExcel();
    }

    @Override
    public ValidateImportBO<RiskHidHiddenDangerExcelDTO> validateImport(List<RiskHidHiddenDangerExcelDTO> excelDTOList) {
        ValidateImportBO<RiskHidHiddenDangerExcelDTO> bo = new ValidateImportBO<>();
        List<ErrorMessage> errorMessageList = new ArrayList<>();
        List<RiskHidHiddenDangerExcelDTO> saveList = new ArrayList<>();
        int successNum = 0;
        int failedNum = 0;
        for (RiskHidHiddenDangerExcelDTO hidHiddenDangerExcelDTO : excelDTOList) {
            String validateRes = ValidatorUtils.validateEntity(hidHiddenDangerExcelDTO);
            if (StrUtil.isEmpty(validateRes)) {
                successNum++;
                saveList.add(hidHiddenDangerExcelDTO);
            } else {
                failedNum++;
                errorMessageList.add(new ErrorMessage(hidHiddenDangerExcelDTO.getLineNum(), new HashSet<String>() {{
                    add(validateRes);
                }}));
            }
        }
        bo.setErrorMessages(errorMessageList);
        bo.setSaveList(saveList);
        bo.setSuccessNum(successNum);
        bo.setFailedNum(failedNum);
        return bo;
    }

    @Override
    public RiskHidHiddenDangerEntity importDtoToEntity(RiskHidHiddenDangerExcelDTO excelDto) {
        RiskHidHiddenDangerEntity entity = new RiskHidHiddenDangerEntity();
        BeanUtils.copyProperties(excelDto, entity);
        entity.setHidLevel(Integer.valueOf(DictResolver.getItemValueByLabel(EnforcementSysDictEnum.danger_level, excelDto.getHidLevel())));
        entity.setHidSource(Integer.valueOf(DictResolver.getItemValueByLabel(EnforcementSysDictEnum.hidden_danger_check_type_and_source, excelDto.getHidSource())));
        entity.setHidType(Integer.valueOf(DictResolver.getItemValueByLabel(EnforcementSysDictEnum.danger_type, excelDto.getHidType())));
        entity.setDeptId(Long.valueOf(DictResolver.getItemValueByLabel(AdminDictEnum.sys_dept, excelDto.getDeptId())));
        // 上报人
        entity.setReportUserId(Long.valueOf(DictResolver.getItemValueByLabel(AdminDictEnum.sys_user, excelDto.getReportUserId())));
        // 延期状态
        entity.setDelayStatus(HidDicConstant.DELAY_STATUS_NORMAL);
        // 隐患审批状态
        entity.setAuditStatus(HidDicConstant.HIDDEN_DANGER_AUDIT_STATUS_NORMAL);
        // 隐患状态待提交
        entity.setHidStatus(HidDicConstant.HID_DANGER_STATUS_WAIT_SUBMIT);
        return entity;
    }

    @Override
    public RiskHidHiddenDangerExcelVO exportEntityToVo(RiskHidHiddenDangerEntity entity) {
        RiskHidHiddenDangerExcelVO excelVO = new RiskHidHiddenDangerExcelVO();
        BeanUtils.copyProperties(entity, excelVO);
        return excelVO;
    }

    @Override
    public Long handleHidSave(RiskHidHiddenDangerDTO hidHiddenDangerDto) {
        //校验
        if (hidHiddenDangerDto.getAssignFlag()) {
            ValidatorUtils.validateEntity(hidHiddenDangerDto, HidAssignGroup.class);
        }
        //保存数据
        RiskHidHiddenDangerEntity wrapper = new RiskHidHiddenDangerEntity();
        BeanUtils.copyProperties(hidHiddenDangerDto, wrapper);
        // 填充默认数据
        wrapper.setHidStatus(HidDicConstant.HID_DANGER_STATUS_WAIT_SUBMIT);
        wrapper.setDelayStatus(HidDicConstant.DELAY_STATUS_NORMAL);
        wrapper.setAuditStatus(HidDicConstant.HIDDEN_DANGER_AUDIT_STATUS_NORMAL);
        wrapper.setReportDate(new Date());
        wrapper.setHidCode(getHidCode());
        baseMapper.insert(wrapper);

        // 隐患上报积分事件
        final RiskHidHiddenDangerEntity riskHidHiddenDangerEntity = baseMapper.selectById(wrapper.getId());
        TenantBroker.runAs(riskHidHiddenDangerEntity.getTenantId(), (id) -> {
            final IntegralEvent integralEvent = new IntegralEvent();
            integralEvent.setBusinessId(wrapper.getId());
            integralEvent.setModule(IntegralEventEnum.hid_report_integral);
            eventPublisher.publishEvent(integralEvent);
        });

        return wrapper.getId();
    }

    @Override
    public void handleHidUpdate(RiskHidHiddenDangerDTO hidHiddenDangerDto) {
        // 校验
        Long id = hidHiddenDangerDto.getId();
        RiskHidHiddenDangerEntity hidHiddenDanger = this.getById(id);
        Integer hidStatus = hidHiddenDanger.getHidStatus();
        if (!HidDicConstant.HID_DANGER_STATUS_WAIT_SUBMIT.equals(hidStatus)) {
            throw new BizException("修改失败,该隐患已经提交!");
        }

        if (hidHiddenDangerDto.getAssignFlag()) {
            ValidatorUtils.validateEntity(hidHiddenDangerDto, HidAssignGroup.class);
        }
        //更新
        RiskHidHiddenDangerEntity hiddenDanger = new RiskHidHiddenDangerEntity();
        BeanUtils.copyProperties(hidHiddenDangerDto, hiddenDanger);
        baseMapper.updateById(hiddenDanger);
    }

    @Override
    @GlobalTransactional // 分布式事务注解
    public Long handleHidSaveAndSubmit(RiskHidHiddenDangerDTO hidHiddenDangerDto) {
        // 保存
        Long hidId = SpringUtil.getBean(RiskHidHiddenDangerService.class).handleHidSave(hidHiddenDangerDto);
        // 提交
        SpringUtil.getBean(RiskHidHiddenDangerService.class).handleHidSubmit(hidId);
        return hidId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void handleHidSubmit(Long id) {
        RiskHidHiddenDangerEntity riskHidHiddenDanger = getById(id);
        if (!HidDicConstant.HID_DANGER_STATUS_WAIT_SUBMIT.equals(riskHidHiddenDanger.getHidStatus())) {
            throw new BizException("提交隐患失败,该隐患已经提交!");
        }

        RiskHidTaskBo riskHidTaskBo = new RiskHidTaskBo()
                .setHandlePhoto(riskHidHiddenDanger.getReportPhoto());
        TaskExecute taskExecute = new TaskExecute.Build()
                .setBusinessKey(id)
                .setFlowTaskHandlerType(FlowTaskHandlerType.TASK_HANDLE_TYPE_SUBMIT)
                .setBusinessData(riskHidTaskBo)
                .build();
        executeTask(taskExecute);
    }

    @Override
    @GlobalTransactional // 分布式事务注解
    public void handleHidConfirm(RiskHandleHidConfirmDTO handleHidConfirmDto) {
        Long id = handleHidConfirmDto.getId();
        // 校验
        FlowTaskHandlerType flowTaskHandlerType = FlowTaskHandlerType.getFlowTaskHandlerTypeByCode(handleHidConfirmDto.getHandleResult());
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS.equals(flowTaskHandlerType)) {
            ValidatorUtils.validateEntity(handleHidConfirmDto, AuditPassGroup.class);
        } else {
            ValidatorUtils.validateEntity(handleHidConfirmDto, AuditRejectGroup.class);
        }

        // 更新
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS.equals(flowTaskHandlerType)) {
            lambdaUpdate().set(RiskHidHiddenDangerEntity::getCorrectiveWay, handleHidConfirmDto.getCorrectiveWay())
                    .set(RiskHidHiddenDangerEntity::getCorrectiveDesc, handleHidConfirmDto.getCorrectiveDesc())
                    .set(RiskHidHiddenDangerEntity::getCorrectiveAdviceDesc, handleHidConfirmDto.getCorrectiveAdviceDesc())
                    .set(RiskHidHiddenDangerEntity::getCorrectiveDeadline, handleHidConfirmDto.getCorrectiveDeadline())
                    .set(RiskHidHiddenDangerEntity::getPrincipal, handleHidConfirmDto.getPrincipal())
                    .set(RiskHidHiddenDangerEntity::getConfirmUserId, SecurityUtils.getUserId())
                    .set(RiskHidHiddenDangerEntity::getCompanyId,handleHidConfirmDto.getCompanyId())
                    .eq(RiskHidHiddenDangerEntity::getId, id)
                    .update();
        }

        // 提交工作流
        RiskHidTaskBo riskHidTaskBo = new RiskHidTaskBo()
                .setHandleResultDesc(handleHidConfirmDto.getHandleResultDesc());
        TaskExecute taskExecute = new TaskExecute.Build()
                .setBusinessKey(id)
                .setFlowTaskHandlerType(flowTaskHandlerType)
                .setBusinessData(riskHidTaskBo)
                .build();
        executeTask(taskExecute);
    }

    @Override
    @GlobalTransactional // 分布式事务注解
    public void handleHidRectify(RiskHandleHidRectifyDTO handleHidRectifyDto) {
        Long id = handleHidRectifyDto.getId();
        // 校验
        FlowTaskHandlerType flowTaskHandlerType = FlowTaskHandlerType.getFlowTaskHandlerTypeByCode(handleHidRectifyDto.getHandleResult());
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS.equals(flowTaskHandlerType)) {
            ValidatorUtils.validateEntity(handleHidRectifyDto, AuditPassGroup.class);
        } else {
            ValidatorUtils.validateEntity(handleHidRectifyDto, AuditRejectGroup.class);
        }
        // 更新
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS.equals(flowTaskHandlerType)) {
            lambdaUpdate().set(RiskHidHiddenDangerEntity::getCorrectiveReportDesc, handleHidRectifyDto.getCorrectiveReportDesc())
                    .set(RiskHidHiddenDangerEntity::getCorrectiveReportPhoto, handleHidRectifyDto.getCorrectiveReportPhoto())
                    .set(RiskHidHiddenDangerEntity::getCorrectiveUserId, SecurityUtils.getUserId())
                    .eq(RiskHidHiddenDangerEntity::getId, id)
                    .update();

            // 发布积分事件
            final RiskHidHiddenDangerEntity riskHidHiddenDangerEntity = baseMapper.selectById(id);
            TenantBroker.runAs(riskHidHiddenDangerEntity.getTenantId(), (aLong) -> {
                final IntegralEvent integralEvent = new IntegralEvent();
                integralEvent.setBusinessId(id);
                integralEvent.setModule(IntegralEventEnum.hid_rectify_integral);
                eventPublisher.publishEvent(integralEvent);
            });
        }
        // 提交任务
        RiskHidTaskBo riskHidTaskBo = new RiskHidTaskBo()
                .setHandlePhoto(handleHidRectifyDto.getCorrectiveReportPhoto())
                .setHandleResultDesc(handleHidRectifyDto.getHandleResultDesc());
        TaskExecute taskExecute = new TaskExecute.Build()
                .setBusinessKey(id)
                .setFlowTaskHandlerType(flowTaskHandlerType)
                .setBusinessData(riskHidTaskBo)
                .build();
        executeTask(taskExecute);
    }

    @Override
    public void handleHidAcceptance(RiskHandleHidAcceptanceDTO handleHidAcceptanceDto) {
        Long id = handleHidAcceptanceDto.getId();
        //校验
        FlowTaskHandlerType flowTaskHandlerType = FlowTaskHandlerType.getFlowTaskHandlerTypeByCode(handleHidAcceptanceDto.getHandleResult());
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS.equals(flowTaskHandlerType)) {
            ValidatorUtils.validateEntity(handleHidAcceptanceDto, AuditPassGroup.class);
        }
        // 更新
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_PASS.equals(flowTaskHandlerType)) {
            lambdaUpdate().set(RiskHidHiddenDangerEntity::getCheckTime, new Date())
                    .set(RiskHidHiddenDangerEntity::getCheckUserId, SecurityUtils.getUserId())
                    .set(RiskHidHiddenDangerEntity::getCheckUserSignature, handleHidAcceptanceDto.getSignature())
                    .set(RiskHidHiddenDangerEntity::getCheckDesc, handleHidAcceptanceDto.getHandleResultDesc())
                    .eq(RiskHidHiddenDangerEntity::getId, id)
                    .update();
        }
        // 提交任务
        RiskHidTaskBo riskHidTaskBo = new RiskHidTaskBo()
                .setSignature(handleHidAcceptanceDto.getSignature())
                .setHandleResultDesc(handleHidAcceptanceDto.getHandleResultDesc());
        // 提交任务
        TaskExecute taskExecute = new TaskExecute.Build()
                .setBusinessKey(id)
                .setFlowTaskHandlerType(flowTaskHandlerType)
                .setBusinessData(riskHidTaskBo)
                .build();
        executeTask(taskExecute);
    }

    @Override
    public RiskHidHiddenDangerEntity getOneByRiskHid(String code) {
        return this.baseMapper.getOneByRiskHid(code);
    }

    @Override
    public List<Integer> getSafetyHidData(RiskHidHiddenDangerBO danger) {
        return this.baseMapper.getSafetyHidData(danger);
    }

    @Override
    public void doCompletedTask(FlowTaskInfo flowTaskInfo, Long id, FlowTaskHandlerType handlerType, Object data) {
        RiskHidTaskBo riskHidTaskBo = (RiskHidTaskBo) data;
        RiskHidHiddenDangerEntity hidHiddenDanger = this.getById(id);
        Integer hidStatus = hidHiddenDanger.getHidStatus();
        Long curUserId = SecurityUtils.getUserId();
        String desc;
        if (StringUtils.isNotBlank(riskHidTaskBo.getHandleResultDesc())){
            desc = riskHidTaskBo.getHandleResultDesc();
        }else {
            desc = handlerType.getName();
        }
        String handlePhoto = riskHidTaskBo.getHandlePhoto();
        String signature = riskHidTaskBo.getSignature();
        // 创建或更新当前节点
        if (FlowTaskHandlerType.TASK_HANDLE_TYPE_SUBMIT.equals(handlerType)) {
            // 创建提交节点
            RiskHidHandleRecordEntity record = new RiskHidHandleRecordEntity();
            record.setHidId(id);
            record.setHandleDate(new Date());
            record.setExecutor(curUserId.toString());
            record.setHandleUserId(curUserId);
            record.setNodeCode(hidStatus);
            record.setHandleResult(handlerType.getCode().toString());
            record.setHandleResultDesc(desc);
            record.setHandlePhoto(handlePhoto);
            riskHidHandleRecordService.save(record);
        } else {
            //更新上一个节点
            RiskHidHandleRecordEntity preRecord = riskHidHandleRecordService.lambdaQuery()
                    .eq(RiskHidHandleRecordEntity::getHidId, id)
                    .eq(RiskHidHandleRecordEntity::getNodeCode, hidStatus)
                    .orderByDesc(RiskHidHandleRecordEntity::getCreateTime)
                    .select(RiskHidHandleRecordEntity::getId)
                    .last("limit 1")
                    .one();
            riskHidHandleRecordService.lambdaUpdate()
                    .set(StringUtils.isNotBlank(handlePhoto), RiskHidHandleRecordEntity::getHandlePhoto, handlePhoto)
                    .set(StringUtils.isNotBlank(signature), RiskHidHandleRecordEntity::getSignature, signature)
                    .set(StringUtils.isNotBlank(desc), RiskHidHandleRecordEntity::getHandleResultDesc, desc)
                    .set(RiskHidHandleRecordEntity::getHandleResult, handlerType.getCode())
                    .set(RiskHidHandleRecordEntity::getHandleUserId, curUserId)
                    .set(RiskHidHandleRecordEntity::getHandleDate, new Date())
                    .eq(RiskHidHandleRecordEntity::getId, preRecord.getId())
                    .update();
        }
        //创建下一个节点
        RiskHidHandleRecordEntity nextRecord = new RiskHidHandleRecordEntity();
        nextRecord.setHidId(id);
        Integer status = flowTaskInfo.getStatus();
        nextRecord.setNodeCode(status);
        nextRecord.setExecutor(flowTaskInfo.getCandidateStr());
        riskHidHandleRecordService.save(nextRecord);
        // 更新隐患状态
        lambdaUpdate()
                .set(RiskHidHiddenDangerEntity::getHidStatus, status)
                .set(RiskHidHiddenDangerEntity::getAuditStatus, handlerType.getCode())
                .eq(RiskHidHiddenDangerEntity::getId, id)
                .update();
    }

    @Override
    public String getFlowDefinitionKey(Long id) {
        return FlowConstant.HIDDEN_DANGER_PARK;
    }


    @Override
    public void deleteBusiness(Collection<Long> hidList) {
        List<RiskHidHandleRecordEntity> list = riskHidHandleRecordService.lambdaQuery()
                .select(RiskHidHandleRecordEntity::getId)
                .in(RiskHidHandleRecordEntity::getHidId, hidList)
                .list();
        List<Long> idList = list.stream().map(RiskHidHandleRecordEntity::getId).collect(Collectors.toList());
        riskHidHandleRecordService.removeBatchByIds(idList);
        //删除相关的延期申请
        riskHidHiddenDangerDelayService.remove(Wrappers.lambdaQuery(RiskHidHiddenDangerDelayEntity.class).in(RiskHidHiddenDangerDelayEntity::getHiddenDangerId, hidList));
    }

    private String getHidCode() {
        RiskHidHiddenDangerEntity lastHid = lambdaQuery().orderByDesc(RiskHidHiddenDangerEntity::getCreateTime).last("limit 1")
                .select(RiskHidHiddenDangerEntity::getHidCode).one();
        int index = 1;
        if (Objects.nonNull(lastHid)) {
            String hidCode = lastHid.getHidCode();
            index += Integer.parseInt(hidCode.substring(hidCode.lastIndexOf("_") + 1));
        }

        return HidDicConstant.HID_CODE_NAME + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmss") + "_" + index;
    }

    @Override
    public String setSearchKeyword(Long id) {
        RiskHidHiddenDangerEntity riskHidHiddenDanger = getById(id);
        if (ObjectUtil.isNotEmpty(riskHidHiddenDanger)){
            return riskHidHiddenDanger.getHidCode();
        }
        return null;
    }
}
